package com.gitee.fantaros.web.fan.netcut.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.fantaros.web.fan.netcut.mapper.AiMapper;
import com.gitee.fantaros.web.fan.netcut.threading.*;
import com.gitee.fantaros.web.fan.netcut.util.UserSettings;
import com.vaadin.flow.spring.annotation.SpringComponent;
import jakarta.validation.constraints.Min;
import lombok.experimental.NonFinal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

@SpringComponent
@Service
@Slf4j
@SuppressWarnings("unused")
public class DeepSeekService {

    private static final String AI_INFO_TABLE_NAME = "T_AIINFO";
    private final AiMapper aiMapper;
    private final UserSettings userSettings;
    private final AsyncProcessManager asyncProcessManager;
    private final OllamaChatModel ollamaChatModel;

    public DeepSeekService(@Autowired UserSettings userSettings,
                           @Autowired AsyncProcessManager asyncProcessManager,
                           @Autowired AiMapper aiMapper
                           ) {
        this.userSettings = userSettings;
        this.aiMapper = aiMapper;
        this.asyncProcessManager = asyncProcessManager;
        OllamaApi ollamaApi = new OllamaApi(userSettings.getOllamaUri());
        this.ollamaChatModel = OllamaChatModel.builder().ollamaApi(ollamaApi).
                defaultOptions(OllamaOptions.builder().model(userSettings.getModel()).lowVRAM(true).build()).build();
    }

    private FunctionCallback resolve(String name) {
        return FunctionCallback.builder().method(name).build();
    }

    public String sendAsk(String value) {
        try {
            String ollamaUrl = String.join("", "http://", userSettings.getOllamaUrl(), ":",
                userSettings.getOllamaPort(), "/api/generate");
            return ThreadPoolUtil.submitToThreadPool(() -> post(ollamaUrl, value));
        } catch (Exception e) {
            log.error("调用ollama api 失败", e);
            return "请求失败，无法生成结果！";
        }
    }

    public void asyncSendAsk(String value, ResultCallback<String> resultCallback, Processable<String> processable) {
        String ollamaUrl = String.join("", "http://", userSettings.getOllamaUrl(), ":",
                userSettings.getOllamaPort(), "/api/generate");
        asyncProcessManager.async((resultSolver, process) -> {
            Presentable<String> result = new Presentable<>();
            Presentable<Exception> anyException = new Presentable<>();
            try {
                result.set(processWithOllama(value, process));
            } catch (Exception e) {
                anyException.set(e);
            }
            resultSolver.getValue(result, anyException);
        }, resultCallback, processable);
    }

    private String processWithOllama(String value, Processable<String> process) {
        process.processing("连接到Ollama");
        String result = ollamaChatModel.call(value);
        process.processing("连接成功，处理结果");
        return result;
    }

    private String postWithProceesable(String ollamaUrl, String value, Processable<String> process) throws Exception {
        URL url = new URL(ollamaUrl);
        log.info("connect to server : {}" , ollamaUrl);
        process.processing("正在连接服务器");
        HttpURLConnection connection = getHttpURLConnection(value, url);
        int rspCode = connection.getResponseCode();
        if (rspCode > 399) {
            log.warn("server {} connect failed, return code: {}", ollamaUrl, rspCode);
            process.processing("服务器返回状态码异常");
            return "请求失败，无法链接到ollama！";
        }
        log.info("server {} connected return code : {}", ollamaUrl, rspCode);
        process.processing("服务器已连接，处理响应");
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> result = objectMapper.readValue(connection.getInputStream(), new TypeReference<>() {});
        log.info("return message process finished, close connection to {}", ollamaUrl);
        process.processing("处理服务器响应完毕，关闭服务器连接");
        connection.disconnect();
        return String.valueOf(result.getOrDefault("response", "请求失败，未包含正常响应体！"));
    }

    private HttpURLConnection getHttpURLConnection(@NonFinal String value, URL url) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestMethod("POST");
        connection.setUseCaches(true);
        connection.setConnectTimeout(3000);
        connection.addRequestProperty("Content-Type", "application/json;charset=utf-8");
        try (BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()))) {
            bufferedWriter.write(makeContent(value));
            bufferedWriter.flush();
        }
        connection.connect();
        return connection;
    }

    private String makeContent(String orginalMessage) {
        return String.join("", "{\"model\":\"deepseek-r1\",\"prompt\":\"", orginalMessage,
                "\",\"stream\":false}");
    }

    private String post(String ollamaUrl, String body) throws IOException {
        URL url = new URL(ollamaUrl);
        HttpURLConnection connection = getHttpURLConnection(body, url);
        if (connection.getResponseCode() != 200 && connection.getResponseCode() > 399) {
            return "请求失败，无法链接到ollama！";
        }
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> result = objectMapper.readValue(connection.getInputStream(), new TypeReference<>() {});
        connection.disconnect();
        return String.valueOf(result.getOrDefault("response", "请求失败，未包含正常响应体！"));
    }

    public void prepareTables() {
        aiMapper.createAiInfoTable();
        aiMapper.createCounterTable();
    }

    public void insertContent(String token, String content) {
        if (token != null && content != null) {
            int c = aiMapper.selectCountOfCounter(AI_INFO_TABLE_NAME);
            long sortid = 0;
            if (c == 0) {
                aiMapper.insertOneCounter(AI_INFO_TABLE_NAME, sortid);
            } else {
                sortid = aiMapper.selectNextCounter(AI_INFO_TABLE_NAME);
                aiMapper.updateOneCounter(AI_INFO_TABLE_NAME, sortid);
            }
            aiMapper.insertOneAiInfo(token, sortid, content);
        }
    }

    public List<String> selectContents(String token) {
        return aiMapper.selectAllAiInfoForToken(token);
    }


}
